<?

class view_array
{
    private $arr;
    private $cols = array();
    private $name;
    private $fake_cols = array();
    private $hidden_cols = array();
    private $renamed_cols = array();
    private $handlers = array();
    private $row_class_handler = null;
    private $global_handler = null;

    static public function a2t($arr)
    {
        $o = new view_array($arr);
        return $o->htmlView();
    }

    function __construct($arr, $name = false)
    {
        if (!is_array($arr)) $arr= array();
        $this->arr = $arr;
        $this->name = $name;
        if (empty($this->arr)) return;
        $one_row = reset($this->arr);
        if($one_row instanceof tbl__abstract){
            foreach($this->arr as $key => $val)
                $this->arr[$key] = $val->asArray();
        }
        else if (!is_array($one_row)) throw new Exception('not two-dimensional array given');
        $this->cols = array_keys(reset($this->arr));
    }

    public function htmlView()
    {
        if (empty($this->arr)) return;
        $ret = "<table border='1' class='{$this->name}'>";
        $ret .= "<tr>";
        foreach ($this->cols() as $one) {
            if ($this->isColHidden($one)) continue;
            if (isset($this->renamed_cols[$one])) $one = $this->renamed_cols[$one];
            $ret .= "<th>$one</th>";
        }
        $ret .= "</tr>";
        $i = 0;
        foreach ($this->arr as $row_key => $row) {
            $tr_class = ++$i % 2 ? 'odd' : 'even';
            if($this->row_class_handler) $tr_class .= " ".call_user_func($this->row_class_handler, $row);
            $ret .= "<tr class='$tr_class'>";
            foreach ($this->cols() as $col_key) {
                if ($this->isColHidden($col_key)) continue;
                $ret .= "<td class='$col_key'>" . $this->getCellValue($row_key, $col_key) . "</td>";
            }
            $ret .= "</tr>";
        }
        $ret .= "</table>";
        return $ret;
    }

    public function divView()
    {
        if (empty($this->arr)) return;
        $ret = "<div class='{$this->name}'>";
        foreach ($this->arr as $row_key => $row) {
            $tr_class = ++$i % 2 ? 'odd' : 'even';
            if($this->row_class_handler) $tr_class .= " ".call_user_func($this->row_class_handler, $row);
            $ret .= "<div class='row $tr_class'>";
            foreach ($this->cols() as $col_key) {
                if ($this->isColHidden($col_key)) continue;
                $ret .= "<div class='item $col_key'>" . $this->getCellValue($row_key, $col_key) . "</div>";
            }
            $ret .= "</div>";
        }
        $ret .= "</div>";
        return $ret;
    }
    
    public function setColPosition($field_name, $position){
        $key = array_search($field_name, $this->cols);
        if(false === $key) return;
        $finfo = $this->cols[$key];
        unset($this->cols[$key]);
        array_splice($this->cols, $position, 0, array($finfo));
    }
    
    
    public function addFakeCol($name, $value_or_callback, $position = 0)
    {
        $this->fake_cols[$name] = $value_or_callback;
        array_splice($this->cols, $position, 0, array($name));
    }

    public function getFakeCellValue($row, $col)
    {
    	if(!isset($this->fake_cols[$col])) return;
        if (is_array($this->fake_cols[$col]))
            return call_user_func($this->fake_cols[$col], $this->arr[$row], $this);
        if (is_callable($this->fake_cols[$col]))
            return $this->fake_cols[$col]($this->arr[$row]);

        $tpl = $this->fake_cols[$col];
        preg_match_all("/\{\%([^\}]+)\}/", $tpl, $matches);
        foreach ($matches[1] as $one)
            $tpl = str_replace("{%$one}", $this->getCellValue($row, $one), $tpl);
        return $tpl;
    }

    public function setHandler($col_name, $func)
    {
        $this->handlers[$col_name] = $func;
    }
    
    public function setRowClassHandler($func){
        $this->row_class_handler = $func;
    }
    
    public function setGlobalHandler($func){
        $this->global_handler = $func;
    }

    public function hideCol($column_name){
        $this->hidden_cols[$column_name] = true;
    }
    
    public function keepCols(/*....*/){
        $args = func_get_args();
        foreach($this->cols as $one_col){
            if(in_array($one_col, $args)) continue;
            $this->hideCol($one_col);
        }
    }

    public function renameCol($column_name, $new_name){
        $this->renamed_cols[$column_name] = $new_name;
    }

    private function isColHidden($column_name)
    {
        return isset($this->hidden_cols[$column_name]);
    }

    public function getCellValue($row, $col)
    {                           
        if (isset($this->arr[$row][$col])) $val = $this->arr[$row][$col];
        else $val = $this->getFakeCellValue($row, $col);
        if (isset($this->handlers[$col])) $val = call_user_func($this->handlers[$col], $this->arr[$row], $this);
        if (isset($this->global_handler)) $val = call_user_func($this->global_handler, $this->arr[$row][$col]);
        return $val;
    }

    public function cols()
    {
        return $this->cols;
    }

    static private $sort_field;

    public function sort($column_name, $desc = false)
    {
        self::$sort_field = $column_name;
        usort($this->arr, "SimpleArrayView::cmp");
    }

    static private function cmp($a, $b)
    {
        self::$sort_field;
        if ($a[self::$sort_field] == $b[self::$sort_field]) {
            return 0;
        }
        return ($a[self::$sort_field] < $b[self::$sort_field]) ? -1 : 1;
    }
}

?>
